﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Text.RegularExpressions;

namespace Slqj.Common
{
    #region Post
    public delegate object QueryPagingDataHandler(PostPagingMgr pagingMgr);
    public class PostPagingMgrUIUpdateEventArgs : EventArgs
    {
        object m_dataSource;

        public object DataSource
        {
            get { return m_dataSource; }
        }

        PostPagingMgr m_pagingMgr;

        public PostPagingMgr PagingMgr
        {
            get { return m_pagingMgr; }
        }

        public PostPagingMgrUIUpdateEventArgs(object dataSource, PostPagingMgr pagingMgr)
        {
            m_dataSource = dataSource;
            m_pagingMgr = pagingMgr;
        }
    }

    /// <summary>
    /// Paging Using ViewState
    /// </summary>
    public class PostPagingMgr
    {
        string m_uid = string.Empty;
        const string CURRENT_PAGE_KEY_PREFIX = "PostPagingMgr_CurrentPage_Key_";
        const string TOTAL_PAGES_KEY_PREFIX = "PostPagingMgr_TotalPages_Key_";
        const string TOTAL_RECORDS_KEY_PREFIX = "PostPagingMgr_TotalRecords_Key_";
        const string OTHER_KEY_PREFIX_PREFIX = "PostPagingMgr_OtherKey_P_";
        string CURRENT_PAGE_KEY { get { return CURRENT_PAGE_KEY_PREFIX + m_uid; } }
        string TOTAL_PAGES_KEY { get { return TOTAL_PAGES_KEY_PREFIX + m_uid; } }
        string TOTAL_RECORDS_KEY { get { return TOTAL_RECORDS_KEY_PREFIX + m_uid; } }
        string OTHER_KEY_PREFIX { get { return OTHER_KEY_PREFIX_PREFIX + m_uid; } }

        int m_pageSize;

        public int PageSize
        {
            get { return m_pageSize; }
        }
        StateBag m_viewState;
        QueryPagingDataHandler m_queryData;
        public event EventHandler<PostPagingMgrUIUpdateEventArgs> OnUpdateUI;


        public PostPagingMgr(string uid, int pageSize, StateBag viewState, QueryPagingDataHandler queryData)
        {
            m_uid = uid;
            m_pageSize = pageSize;
            m_viewState = viewState;
            m_queryData = queryData;
        }

        public PostPagingMgr(int pageSize, StateBag viewState, QueryPagingDataHandler queryData)
            : this(string.Empty, pageSize, viewState, queryData)
        {
            
        }

        #region Paging Data Properties

        public int CurrentPage
        {
            get { return m_viewState[CURRENT_PAGE_KEY] == null ? 0 : (int)m_viewState[CURRENT_PAGE_KEY]; }
            set { m_viewState[CURRENT_PAGE_KEY] = value; }
        }

        public int TotalPages
        {
            get { return m_viewState[TOTAL_PAGES_KEY] == null ? 0 : (int)m_viewState[TOTAL_PAGES_KEY]; }
            set { m_viewState[TOTAL_PAGES_KEY] = value; }
        }

        public long TotalRecords
        {
            get { return m_viewState[TOTAL_RECORDS_KEY] == null ? 0 : (long)m_viewState[TOTAL_RECORDS_KEY]; }
            set { m_viewState[TOTAL_RECORDS_KEY] = value; }
        }

        public object GetParameter(string key)
        {
            return m_viewState[OTHER_KEY_PREFIX + key];
        }

        public void SetParameter(string key, object val)
        {
            m_viewState[OTHER_KEY_PREFIX + key] = val;
        }

        #endregion

        public void Reset(long totalRecords, int startPage)
        {
            TotalRecords = totalRecords;
            TotalPages = (int)Math.Ceiling(TotalRecords / (double)m_pageSize);
            if (TotalPages <= 0)
            {
                CurrentPage = 0;
                CallOnUpdate(null);
                return;
            }
            if (!CheckGoPage(startPage))
                startPage = TotalPages;
            CurrentPage = startPage;
            CallOnUpdate(m_queryData(this));
        }

        public void Reset(long totalRecords)
        {
            Reset(totalRecords, 1);
        }

        #region Operations

        private void CallOnUpdate(object dataSource)
        {
            if (null != OnUpdateUI)
                OnUpdateUI(this, new PostPagingMgrUIUpdateEventArgs(dataSource, this));
        }

        public bool CheckGoPage(int page)
        {
            if (page < 1 || page > TotalPages || TotalRecords <= 0)
                return false;
            return true;
        }

        public void GoPage(int page)
        {
            if(!CheckGoPage(page))
            {
                //CallOnUpdate(null);
                return;
            }
            CurrentPage = page;
            CallOnUpdate(m_queryData(this));
        }

        public void GoFirstPage()
        {
            GoPage(1);
        }

        public bool CheckPrevPage()
        {
            return CheckGoPage(CurrentPage - 1);
        }

        public void GoPrevPage()
        {
            GoPage(CurrentPage - 1);
        }

        public bool CheckNextPage()
        {
            return CheckGoPage(CurrentPage + 1);
        }

        public void GoNextPage()
        {
            GoPage(CurrentPage + 1);
        }

        public void GoLastPage()
        {
            GoPage(TotalPages);
        }

        public void RefreshPage()
        {
            GoPage(CurrentPage);
        }
        #endregion
    }

    #endregion

    #region Get
    public struct GetPagingMgrParam 
    {
        public string Name;
        public string Value;
        public GetPagingMgrParam(string name, string value)
        {
            Name = name;
            Value = value;
        }
    }

    public class GetPagingMgrParamDic
        : Dictionary<string, string>
    {
        public new string this[string key]
        {
            get { return base.ContainsKey(key) ? base[key] : null; }
            set { base[key] = value; }
        }
    }

    public delegate string GenPagingUrlHandler(string url, int newPage, GetPagingMgrParamDic paramDic);
    
    public class GetPagingMgr
    {
        string m_uniqueID;
        public string UniqueID
        {
            get { return string.IsNullOrEmpty(m_uniqueID) ? "" : "_" + m_uniqueID + "_"; }
        }

        public string CurrentPageKey
        {
            get { return UniqueID + "cp"; }
        }

        int m_currentPage;
        /// <summary>
        /// Current Page
        /// </summary>
        public int CurrentPage
        {
            get { return m_currentPage; }
        }

        int m_pageSize;
        /// <summary>
        /// Page Size
        /// </summary>
        public int PageSize
        {
            get { return m_pageSize; }
            set { m_pageSize = value; }
        }

        int m_totalPages;
        /// <summary>
        /// 
        /// </summary>
        public int TotalPages
        {
            get { return m_totalPages; }
        }

        long m_totalRecords;
        /// <summary>
        /// 
        /// </summary>
        public long TotalRecords
        {
            get { return m_totalRecords; }
            set
            {
                m_totalRecords = value;
                m_totalPages = (int)Math.Ceiling(m_totalRecords / (double)m_pageSize);
                int.TryParse(HttpContext.Current.Request.QueryString[CurrentPageKey], out m_currentPage);
                if (m_currentPage <= 1)
                {
                    if (m_totalPages <= 0)
                        m_currentPage = 0;
                    else
                        m_currentPage = 1;
                }
            }
        }

        GenPagingUrlHandler m_genPageFun;
        /// <summary>
        /// 
        /// </summary>
        public GenPagingUrlHandler GenPageFun
        {
            get { return m_genPageFun; }
            set { m_genPageFun = value; }
        }

        Dictionary<string, string> m_params = new Dictionary<string, string>();
        /// <summary>
        /// 
        /// </summary>
        public Dictionary<string, string> Params
        {
            get { return m_params; }
        }

        public GetPagingMgr(string uniqueId, int pageSize)
        {
            m_uniqueID = uniqueId;
            m_pageSize = pageSize;
            m_genPageFun = _GenUrl;
            //get params
            foreach (string key in HttpContext.Current.Request.QueryString.AllKeys)
            {
                string o = HttpContext.Current.Request.QueryString[key];
                if (o == null || key == null || key.Equals(CurrentPageKey) || key.IndexOf(UniqueID) != 0)
                    continue;
                m_params[key.Substring(UniqueID.Length)] = Decode((string)o);
            }
        }

        public static string Encode(string str)
        {
            try
            {
                return str == null ? "" : HttpServerUtility.UrlTokenEncode(UTF8Encoding.UTF8.GetBytes(str));
            }
            catch
            {
                return "";
            }
            
        }

        public static string Decode(string strEncode)
        {
            try
            {
                byte[] buf = HttpServerUtility.UrlTokenDecode(strEncode);
                return buf == null ? strEncode : UTF8Encoding.UTF8.GetString(buf);
            }
            catch
            {
                return strEncode;
            }
        }

        public GetPagingMgrParam CreateParam(string name, string value)
        {
            return new GetPagingMgrParam(name, value);
        }

        public string GetParameter(string key)
        {
            return m_params.ContainsKey(key) ? m_params[key] : "";
        }

        public string GetParameterEncode(string key)
        {
            return Encode((string)GetParameter(key));
        }

        public void SetParameter(string key, string val)
        {
            m_params[key] = val == null ? "" : val.ToString();
        }


        public static string AppendUrl(string url, string key, string val)
        {
            string ptn = "[?&]" + key + "=[^?&/]*";
            if (Regex.IsMatch(url, ptn))
                url = Regex.Replace(url, ptn, "");
            return url += (url.Contains("?") ? "&" : "?") + key + "=" + val;
        }


        /// <summary>
        /// Gen Url
        /// </summary>
        public string _GenUrl(string url, int newPage, GetPagingMgrParamDic paramDic)
        {
            if(newPage > 0)
                url = AppendUrl(url, CurrentPageKey, newPage.ToString());
            foreach (KeyValuePair<string, string> pos in paramDic)
                url = AppendUrl(url, pos.Key, pos.Value);
            return url;
        }
       
        public string GetUrl(string url, bool isResetParams, int newCurrentPage, params GetPagingMgrParam[] newParams)
        {
            GetPagingMgrParamDic paramDic = new GetPagingMgrParamDic();
            //append current params
            if (!isResetParams)
                foreach (KeyValuePair<string, string> pos in m_params)
                    paramDic[UniqueID + pos.Key] = Encode(pos.Value);

            //append new 
            foreach (GetPagingMgrParam p in newParams)
                paramDic[UniqueID + p.Name] = Encode(p.Value);

            //append request query string
            foreach(string key in HttpContext.Current.Request.QueryString.AllKeys)
            {
                if (key == null || key.IndexOf(UniqueID) == 0)
                    continue;
                paramDic[key] = HttpContext.Current.Request.QueryString[key];
            }

            return m_genPageFun(url, newCurrentPage, paramDic);
        }

        public string GetUrl(bool isResetParams, int newCurrentPage, params GetPagingMgrParam[] newParams)
        {
            return GetUrl(HttpContext.Current.Request.Path, isResetParams, newCurrentPage, newParams);
        }

        public bool CheckGoPage(int page)
        {
            return !(page < 1 || page > TotalPages || TotalRecords <= 0 || CurrentPage == page);
        }

        public string GetPageUrl(int page, string defaultUrl)
        {
            if(defaultUrl != null)
                if (!CheckGoPage(page))
                    return defaultUrl;
            return GetUrl(HttpContext.Current.Request.Path, false, page);
        }

        public string GetFirstPageUrl(string defaultUrl)
        {
            return GetPageUrl(1, defaultUrl);
        }

        public string GetFirstPageUrl()
        {
            return GetPageUrl(1, "javascript:void(0);");
        }

        public string GetPrevPageUrl(string defaultUrl)
        {
            return GetPageUrl(CurrentPage - 1, defaultUrl);
        }

        public string GetPrevPageUrl()
        {
            return GetPageUrl(CurrentPage - 1, "javascript:void(0);");
        }

        public string GetNextPageUrl(string defaultUrl)
        {
            return GetPageUrl(CurrentPage + 1, defaultUrl);
        }

        public string GetNextPageUrl()
        {
            return GetPageUrl(CurrentPage + 1, "javascript:void(0);");
        }

        public string GetLastPageUrl(string defaultUrl)
        {
            return GetPageUrl(TotalPages, defaultUrl);
        }

        public string GetLastPageUrl()
        {
            return GetPageUrl(TotalPages, "javascript:void(0);");
        }

        public string GetRefreshPageUrl(string defaultUrl)
        {
            return GetPageUrl(CurrentPage, defaultUrl);
        }

        public string GetRefreshPageUrl()
        {
            return GetPageUrl(CurrentPage, "javascript:void(0);");
        }
    }
    #endregion
}
